﻿using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
using XLua;
using System.IO;
using System.Collections.Generic;

namespace Kylin
{
    [LuaCallCSharp]
	public class SceneLoader : SingletonMonobehaviour<SceneLoader>
    {
		AsyncOperation asyncOperation;
		System.Action<int> funcUpdate;
		System.Action funcComplete;
		bool loading = false;

        List<string> loadedSceneList = new List<string>();

		public void LoadScene(string sceneName, bool additive, System.Action funcStart = null, System.Action<int> funcUpdate = null, System.Action funcComplete = null, System.Action<string> error = null)
        {
			if (loading) {
				Debug.LogError ("另外一个场景还在加载中，不能执行任务。");
				return;
			}

            for (int i = 0; i < loadedSceneList.Count; ++i)
            {
                if (loadedSceneList[i].Equals(sceneName))
                {
                    Debug.LogWarning("场景 [" + sceneName + "] 已经加载过。不能重复加载。" );
                    return;
                }
            }

            if (null != funcStart)
            {
                funcStart();
                funcStart = null;
            }
            try
            {
                this.funcUpdate = funcUpdate;
                this.funcComplete = funcComplete;
                StartCoroutine(LoadAsync(sceneName, additive));
				loading = true;
            }
            catch (System.Exception e)
            {
                if (null != error)
                {
                    error("加载场景 [" + sceneName + "] 发生异常，具体信息" + e.ToString());
                }

				loading = false;
            }
        }

		private IEnumerator LoadAsync(string sceneName, bool additive)
		{
#if UNITY_EDITOR
            bool useResources = true;
            
            useResources = PlayerPrefs.GetString("ResourceLoadTypeKey") == "Resources";
            if (useResources)
            {
                if (additive)
                {
                    asyncOperation = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
                }
                else
                {
                    asyncOperation = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single);
                }
                asyncOperation.allowSceneActivation = false;

                yield return asyncOperation;
            }
            else
            {
#endif
                if (!additive)
                {
                    List<string> sceneToRemove = new List<string>(loadedSceneList.ToArray());
                    loadedSceneList.Clear();

                    for (int i = 0; i < sceneToRemove.Count; ++i)
                    {
                        AssetManager.UnloadSceneAsset(sceneToRemove[i]);
                    }
                }
                
                string path = AssetManager.LoadSceneAsset(sceneName);
                if (string.IsNullOrEmpty(path))
                {
                    Debug.LogError("Load scene error, scene name is: " + sceneName);
                    yield break;
                }
                else
                {
                    loadedSceneList.Add(sceneName);

                    if (additive)
                    {
                        asyncOperation = SceneManager.LoadSceneAsync(path, LoadSceneMode.Additive);
                    }
                    else
                    {
                        asyncOperation = SceneManager.LoadSceneAsync(path, LoadSceneMode.Single);
                    }
                    
                    yield return asyncOperation;
                }

#if UNITY_EDITOR
            }
#endif
        }

        void Update()
        {
            if (null == asyncOperation)
                return;

            if (null != funcUpdate && asyncOperation.progress <= 0.9f)
            {
                funcUpdate((int)((asyncOperation.progress + 0.1f) * 100));
            }

            if (asyncOperation.progress == 0.9f)
            {
                asyncOperation.allowSceneActivation = true;

                if(null != funcUpdate)
                    funcUpdate(100);
            }

            if (asyncOperation.isDone)
            {                
                asyncOperation = null;

                if(null != funcComplete)
                funcComplete();

                funcUpdate = null;
                funcComplete = null;

                loading = false;
            }
        }
    }
}
